//
//  MCNetworking.m
//  iMooc
//
//  Created by CoderXSLee on 13/5/3.
//  Copyright © 2013年 李雪松. All rights reserved.
//

#import "MCNetworking.h"
#import "MCResponseTool.h"
#import "MCNetworkMonitoring.h"

#if __has_include(<AFNetworking/AFNetworking.h>)
#import <AFNetworking/AFNetworking.h>
#elif __has_include("AFNetworking.h")
#import "AFNetworking.h"
#endif

#if __has_include(<AFNetworking/AFNetworkActivityIndicatorManager.h>)
#import <AFNetworking/AFNetworkActivityIndicatorManager.h>
#elif __has_include("AFNetworkActivityIndicatorManager.h")
#import "AFNetworkActivityIndicatorManager.h"
#endif

#ifdef DEBUG
//#define MCLog(...) NSLog(__VA_ARGS__)
#define MCLog(fmt,...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__,__LINE__,##__VA_ARGS__);
#else
#define MCLog(...)
#endif

#define networking [MCNetworking sharedInstance]

static MCNetworking *_instace = nil;
static NSString *_baseURLString = nil;

@interface MCNetworking ()

@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;

@end

@implementation MCNetworking

#pragma mark - 拒绝使用代理请求网络的失败结果
+ (void)rejectProxyRequestWithURL:(NSString *)url httpMethod:(NSString *)method param:(NSDictionary *)param networkBlock:(NetworkBlock)networkBlock {
    NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:15791 userInfo:nil];
    NSURL *fullUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", _baseURLString, url]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fullUrl];
    request.HTTPMethod = method;
    NSMutableDictionary *muparam = [NSMutableDictionary dictionaryWithDictionary:param];
    [muparam setValue:@"禁止使用代理，请关闭后尝试" forKey:@"error"];
    request.HTTPBody = [NSJSONSerialization dataWithJSONObject:muparam options:0 error:nil];
    MCCommonResult *result = [MCCommonResult resultWithCode:MC_RESULT_FAILURE desc:@"请求失败" request:request];
    if (networkBlock) { networkBlock(result, error); }
}

#pragma mark - Public Methods
/// 适用于传参方式 例如: www.baidu.com/getUserAddressList/1207 (1207为UID)
+ (void)GET:(NSString *)urlString networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        [self rejectProxyRequestWithURL:urlString httpMethod:@"GET" param:nil networkBlock:networkBlock];
        return;
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager GET:urlString parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        MCLog(@"接口: %@%@ 以【GET】方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        MCLog(@"接口: %@%@ 以【GET】方式->请求失败!", _baseURLString, urlString);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// 适用于 REST URI 例如: www.baidu.com/getUserAddressList/?userID=1207
+ (void)GET:(NSString *)urlString parameters:(NSDictionary *)parameters networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        [self rejectProxyRequestWithURL:urlString httpMethod:@"GET" param:parameters networkBlock:networkBlock];
        return;
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager GET:urlString parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        MCLog(@"接口: %@%@ 以【GET URI】方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        MCLog(@"接口: %@%@ 以【POST】方式->请求失败! parameters = %@", _baseURLString, urlString, parameters);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// POST 请求
+ (void)POST:(NSString *)urlString parameters:(NSDictionary *)parameters networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        [self rejectProxyRequestWithURL:urlString httpMethod:@"POST" param:parameters networkBlock:networkBlock];
        return;
    }
    if (parameters == nil && networking.isRepaceParame == YES) {
        parameters = @{};
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager POST:urlString parameters:parameters headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        MCLog(@"接口: %@%@ 以【POST】方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        MCLog(@"接口: %@%@ 以【POST】方式->请求失败! parameters = %@", _baseURLString, urlString, parameters);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// 上传文件 POST请求
+ (void)POST:(NSString *)urlString parameters:(NSDictionary *)parameters data:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        NSMutableDictionary *param = [NSMutableDictionary dictionaryWithDictionary:parameters];
        [param setValue:data forKey:@"upload_data"];
        [param setValue:name forKey:@"upload_name"];
        [param setValue:fileName forKey:@"fileName"];
        [self rejectProxyRequestWithURL:urlString httpMethod:@"POST" param:parameters networkBlock:networkBlock];
        return;
    }
    if (parameters == nil && networking.isRepaceParame == YES) {
        parameters = @{};
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager POST:urlString parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileData:data name:name fileName:fileName mimeType:mimeType];
    } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        MCLog(@"接口: %@%@ 以【POST】上传方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        MCLog(@"接口: %@%@ 以【POST】上传方式->请求失败! parameters = %@", _baseURLString, urlString, parameters);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// 上传文件POST请求
+ (void)POST:(NSString *)urlString parameters:(NSDictionary *)parameters constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block fileName:(NSString *)fileName progress:(void(^)(NSProgress *uploadProgress))uploadProgressBlock networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        [self rejectProxyRequestWithURL:urlString httpMethod:@"POST" param:parameters networkBlock:networkBlock];
        return;
    }
    if (parameters == nil && networking.isRepaceParame == YES) {
        parameters = @{};
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager POST:urlString parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        if (block) { block(formData); }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (uploadProgressBlock) { uploadProgressBlock(uploadProgress); }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        MCLog(@"接口: %@%@ 以【POST】上传方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        MCLog(@"接口: %@%@ 以【POST】上传方式->请求失败! parameters = %@", _baseURLString, urlString, parameters);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// PUT 请求
+ (void)PUT:(NSString *)urlString parameters:(NSDictionary *)parameters networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        [self rejectProxyRequestWithURL:urlString httpMethod:@"PUT" param:parameters networkBlock:networkBlock];
        return;
    }
    if (parameters == nil && networking.isRepaceParame == YES) {
        parameters = @{};
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager PUT:urlString parameters:parameters headers:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        MCLog(@"接口: %@%@【PUT】方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        MCLog(@"接口: %@%@ 以【PUT】方式->请求失败! parameters = %@", _baseURLString, urlString, parameters);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// DELETE 请求
+ (void)DELETE:(NSString *)urlString parameters:(NSDictionary *)parameters networkBlock:(NetworkBlock)networkBlock {
    if ([MCNetworking isSetProxy] && networking.available == NO) {
        [self rejectProxyRequestWithURL:urlString httpMethod:@"DELETE" param:parameters networkBlock:networkBlock];
        return;
    }
    if (parameters == nil && networking.isRepaceParame == YES) {
        parameters = @{};
    }
    urlString = [urlString stringByReplacingOccurrencesOfString:@" " withString:@""];
    [networking.sessionManager DELETE:urlString parameters:parameters headers:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        MCLog(@"接口: %@%@ 以【DELETE】方式->请求成功!", _baseURLString, urlString);
        [MCNetworking successWithTask:task response:responseObject networkBlock:networkBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        MCLog(@"接口: %@%@ 以【DELETE】方式->请求失败! parameters = %@", _baseURLString, urlString, parameters);
        [MCNetworking failureWithURLTask:task error:error networkBlock:networkBlock];
    }];
}

/// 根据url取消请求
+ (void)cancelNetworkingWithUrlString:(NSString *)url {
    NSString *urlString = [NSString stringWithFormat:@"%@%@", _baseURLString, url];
    NSArray *tasks = networking.sessionManager.tasks;
    for (NSURLSessionTask *task in tasks) {
        if ([[task.currentRequest.URL absoluteString] isEqualToString:urlString]) {
            [task cancel];
        }
    }
}

/// 取消所有的网络请求
+ (void)cancelAllRequest {
    [networking.sessionManager.tasks makeObjectsPerformSelector:@selector(cancel)];
}

#pragma mark - Private Methods 私有方法内部使用
/// 请求成功的处理
+ (void)successWithTask:(NSURLSessionDataTask *)task response:(id)response networkBlock:(NetworkBlock)block  {
    NSURLRequest *request = task.originalRequest?task.originalRequest:task.currentRequest;
    MCCommonResult *result = [MCCommonResult resultWithCode:MC_RESULT_SUCCESS desc:nil request:request];
    if (block) { block(result, response); }
}

/// 请求失败的处理
+ (void)failureWithURLTask:(NSURLSessionDataTask *)task error:(NSError *)error networkBlock:(NetworkBlock)block {
    NSURLRequest *request = task.originalRequest?task.originalRequest:task.currentRequest;
    MCCommonResult *result = [MCCommonResult resultWithCode:MC_RESULT_FAILURE desc:@"请求失败" request:request];
    if (block) { block(result, error); }
}

/// https  请求第一步，下载Cer证书
+ (void)requestCertWithUrl:(NSString *)url completion:(void (^)(BOOL result))completion {
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSLog(@"--->%@", docPath);
    NSString *certDirPath = [docPath stringByAppendingPathComponent:@"Cert"];
    NSString *certTxtPath = [certDirPath stringByAppendingPathComponent:@"CertTxt.txt"];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager createDirectoryAtPath:certDirPath withIntermediateDirectories:YES attributes:nil error:nil];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:_baseURLString]];
    request.HTTPMethod = @"POST";
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
            if ([dic[@"errorCode"] intValue] == 0) {
                NSString *certFileURL = dic[@"data"];
                if ([fileManager fileExistsAtPath:certTxtPath] && [fileManager fileExistsAtPath:[certDirPath stringByAppendingPathComponent:@"bemm.cer"]]) {
                    NSString *localCertFileURL = [NSString stringWithContentsOfFile:certTxtPath encoding:NSUTF8StringEncoding error:nil];
                    if ([certFileURL isEqualToString:localCertFileURL]) {
                        completion(YES);
                        return ;
                    }
                }
                //下载证书
                NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:certFileURL]];
                NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    if (!error) {
                        [data writeToFile:[certDirPath stringByAppendingPathComponent:@"bemm.cer"] atomically:YES];
                        [certFileURL writeToFile:certTxtPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
                        completion(YES);
                        return ;
                    } else {
                        completion(NO);
                        return ;
                    }
                }];
                [task resume];
            } else {
                completion(NO);
                return ;
            }
        } else {
            completion(NO);
            return;
        }
    }];
    [task resume];
}

#pragma mark - Getters And Setters 存取
- (AFHTTPSessionManager *)sessionManager {
    if (_sessionManager == nil) {
        
        if (_baseURLString.length < 1) {
            NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
            _sessionManager = [[AFHTTPSessionManager manager] initWithBaseURL:url];
        }else {
            NSURL *url = [NSURL URLWithString:_baseURLString];
            _sessionManager = [[AFHTTPSessionManager manager] initWithBaseURL:url];
        }
        _sessionManager.requestSerializer.timeoutInterval = 30;
        
        _sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
        _sessionManager.securityPolicy.allowInvalidCertificates = YES;
        [_sessionManager.securityPolicy setValidatesDomainName:NO];
        
        _sessionManager.requestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:NSJSONWritingFragmentsAllowed];
        [_sessionManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        [_sessionManager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-type"];
        AFJSONResponseSerializer *response = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingFragmentsAllowed];
        // Whether to remove keys with `NSNull` values from response JSON. Defaults to `NO`.
        response.removesKeysWithNullValues = YES;
        _sessionManager.responseSerializer = response;
        [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
    }
    return _sessionManager;
}
- (NSString *)baseURL {
    return _baseURLString;
}
- (NSDictionary *)HTTPRequestHeaders {
    return self.sessionManager.requestSerializer.HTTPRequestHeaders;
}
- (void)setBaseURLString:(NSString *)urlString {
    _baseURLString = urlString;
    
    AFSecurityPolicy *security = _instace.sessionManager.securityPolicy;
    AFHTTPRequestSerializer *request = _instace.sessionManager.requestSerializer;
    AFHTTPResponseSerializer *response = _instace.sessionManager.responseSerializer;
    
    NSURL *baseURL = [NSURL URLWithString:_baseURLString];
    _instace.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
    _instace.sessionManager.securityPolicy = security;
    _instace.sessionManager.requestSerializer = request;
    _instace.sessionManager.responseSerializer = response;
}

- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy {
    self.sessionManager.securityPolicy = securityPolicy;
}

- (void)setTimeoutInterval:(NSInteger)TimeoutInterval {
    self.sessionManager.requestSerializer.timeoutInterval = TimeoutInterval;
}
- (void)setHeaderValue:(NSString *)value forKey:(NSString *)key {
    [self.sessionManager.requestSerializer setValue:value forHTTPHeaderField:key];
}

- (void)setEmptyParameIsReplaceEmptyDictionary:(BOOL)replace {
    _isRepaceParame = replace;
}

- (void)AcceptableContentTypes:(NSSet *)acceptableContentTypes {
    [self.sessionManager.responseSerializer setAcceptableContentTypes:acceptableContentTypes];
}
- (void)setResponseObjectCodeKey:(NSString *)codeKey msgKey:(NSString *)msgKey dataKey:(NSString *)dataKey {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setValue:codeKey forKey:@"responseCodeKey"];
    [dict setValue:msgKey forKey:@"responseMessageKey"];
    [dict setValue:dataKey forKey:@"responseDataKey"];
    _responseObjectKeys = dict;
}
- (void)setMCResultCodeDigitalRange:(MCResultCodeDigitalRange)range {
    _codeRange = range;
}
- (void)addParameterValue:(id)value forKey:(NSString *)key {
    NSAssert(NO, @"已弃用");
}

/// 设置为NO后，添加网络代理时，将不会发送网络请求
- (void)setNetworkProxyAvailable:(BOOL)available {
    _available = available;
}

/// 是否设置网络代理
+ (BOOL)isSetProxy {
    NSDictionary *proxySettings = (__bridge NSDictionary *)(CFNetworkCopySystemProxySettings());
    NSArray *proxies = (__bridge NSArray *)(CFNetworkCopyProxiesForURL((__bridge CFURLRef _Nonnull)([NSURL URLWithString:@"http://www.baidu.com&quot"]), (__bridge CFDictionaryRef _Nonnull)(proxySettings)));
    NSDictionary *settings = proxies[0];
    BOOL isSetProxy = ![[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"];
//    MCLog(@"%@", isSetProxy?@"设置代理":@"没设置代理");
//    MCLog(@"%@",[settings objectForKey:(NSString *)kCFProxyHostNameKey]);
//    MCLog(@"%@",[settings objectForKey:(NSString *)kCFProxyPortNumberKey]);
//    MCLog(@"%@",[settings objectForKey:(NSString *)kCFProxyTypeKey]);
    return isSetProxy;
}

@end

/// 单例的实现
@implementation MCNetworking (Singleton)

- (instancetype)init {
    if (self = [super init]) {
        [self sessionManager];
        [self setNetworkProxyAvailable:YES];
    }
    return self;
}
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instace = [[super allocWithZone:NULL] init];
//        [_instace setupSessionManager];
    });
    return _instace;
}


- (id)copyWithZone:(NSZone *)zone { return _instace; }
+ (id)allocWithZone:(struct _NSZone *)zone { return [self sharedInstance]; }

@end

